﻿//Copyright (C) 2009  Jaco (ScionBot.com)

//This program is free software: you can redistribute it and/or modify
//it under the terms of the GNU General Public License as published by
//the Free Software Foundation, either version 3 of the License, or
//(at your option) any later version.

//This program is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//GNU General Public License for more details.

//You should have received a copy of the GNU General Public License
//along with this program.  If not, see <http://www.gnu.org/licenses/>.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Scion;
using Scion.Library.Antiban;
using System.Threading;
using System.Drawing;
using Scion.Library.Advanced;
using Scion.Library.Underlying;
using Scion.Library.RS;

namespace Scion.Library
{
    /// <summary>
    /// Every script should subclass this class. It basically gives quick access for the functions in stub.
    /// </summary>
    public class Superior : Determine
    {
        /// <summary>
        /// Don't use! Use the Stub property instead. This variable is passed through your script.
        /// </summary>
        public Core.Stub baseStub;
        private BufferedImage flag;
        private BufferedImage loading;
        private BufferedImage conn;
        private RS.UI.Inventory inven;
        private RS.UI.ChooseOption option;
        private RS.UI.TopText tText;
        private RS.UI.Tab gTab;
        private RS.UI.Interface inter;
        private RS.UI.ChatText cText;
        private RS.UI.Equipment equip;

        public Superior()
        {
            inven = new RS.UI.Inventory(this);
            option = new RS.UI.ChooseOption(this);
            tText = new RS.UI.TopText(this);
            inter = new RS.UI.Interface(this);
            gTab = new RS.UI.Tab(this);
            cText = new RS.UI.ChatText(this);
            equip = new RS.UI.Equipment(this);
            flag = Decrypt("(2,2)|255,0,0|93,51,17|198,86,4|93,51,17|", true);
            loading = Decrypt("(6,4)|255,255,255|0,0,0|0,0,0|255,255,255|0,0,0|0,0,0|255,255,255|0,0,0|0,0,0|0,0,0|255,255,255|255,255,255|255,255,255|0,0,0|0,0,0|255,255,255|0,0,0|0,0,0|255,255,255|0,0,0|0,0,0|255,255,255|0,0,0|0,0,0|", true);
            conn = Decrypt("(6,4)|255,255,255|0,0,0|0,0,0|255,255,255|0,0,0|255,255,255|255,255,255|0,0,0|0,0,0|255,255,255|0,0,0|255,255,255|255,255,255|0,0,0|0,0,0|255,255,255|255,255,255|255,255,255|255,255,255|0,0,0|0,0,0|255,255,255|0,0,0|255,255,255|", true);
        }

        /// <summary>
        /// The Equipment property is used to manipulate the equipment tab.
        /// </summary>
        public RS.UI.Equipment Equipment
        {
            get
            {
                return equip;
            }
        }

        /// <summary>
        /// The ChatText property is used to get text in the chat window.
        /// </summary>
        public RS.UI.ChatText ChatText
        {
            get
            {
                return cText;
            }
        }

        /// <summary>
        /// The Interface property is used to manipulate the user interface.
        /// </summary>
        public RS.UI.Interface Interface
        {
            get
            {
                return inter;
            }
        }

        /// <summary>
        /// The Tab property is used to manipulate to tab.
        /// </summary>
        public RS.UI.Tab Tab
        {
            get
            {
                return gTab;
            }
        }

        /// <summary>
        /// The Inventory property is used to manipulate the inventory.
        /// </summary>
        public RS.UI.Inventory Inventory
        {
            get
            {
                return inven;
            }
        }

        /// <summary>
        /// The ChooseOption property is used to select an option in the choose option menu.
        /// </summary>
        public RS.UI.ChooseOption ChooseOption
        {
            get
            {
                return option;
            }
        }

        /// <summary>
        /// The TopText property is used to get the current top text.
        /// </summary>
        public RS.UI.TopText TopText
        {
            get
            {
                return tText;
            }
        }

        /// <summary>
        /// The Stub property houses all the extensions in the core. If needed, the stub can be used for
        /// greater manipulation.
        /// </summary>
        public Core.Stub Stub
        {
            get
            {
                return baseStub;
            }
        }

        /// <summary>
        /// The Mouse property is used for mouse input onto the RS Client.
        /// </summary>
        public Core.Mouse Mouse
        {
            get
            {
                return baseStub.mouse;
            }
        }

        /// <summary>
        /// The Keyboard property is used for keyboard input onto the RS Client.
        /// </summary>
        public Core.Keyboard Keyboard
        {
            get
            {
                return baseStub.keyboard;
            }
        }

        /// <summary>
        /// The Graphics property is used for painting the canvas.
        /// </summary>
        public Core.GFX Graphics
        {
            get
            {
                return baseStub.botGraphics;
            }
        }

        /// <summary>
        /// The Script property is used for manipulation on the executed thread your script is running in.
        /// </summary>
        public Core.Script Script
        {
            get
            {
                return baseStub.botScript;
            }
        }

        /// <summary>
        /// The Account property is used for direct access to the account information.
        /// </summary>
        public Core.Account Account
        {
            get
            {
                return baseStub.botAccount;
            }
        }

        /// <summary>
        /// The Canvas property is used for direct access to the canvas.
        /// </summary>
        public Core.Canvas Canvas
        {
            get
            {
                return baseStub.botCanvas;
            }
        }

        /// <summary>
        /// The Log property is used for I/O operations to the bot's log.
        /// </summary>
        public Core.Log Log
        {
            get
            {
                return baseStub.botLog;
            }
        }

        /// <summary>
        /// The Reflection property is used to get valuable RS fields.
        /// </summary>
        public Core.Reflection Reflection
        {
            get
            {
                return baseStub.botReflection;
            }
        }

        /// <summary>
        /// Sleeps the script thread for the interval's value.
        /// </summary>
        /// <param name="interval">How long to sleep (MS).</param>
        public void Sleep(SleepRandom interval)
        {
            Thread.Sleep(interval.random);
        }

        /// <summary>
        /// Converts RGB colour channels into a Color object.
        /// </summary>
        /// <param name="r">The red channel.</param>
        /// <param name="g">The green channel.</param>
        /// <param name="b">The blue channel.</param>
        public Color FromRGB(int r, int g, int b)
        {
            return Color.FromArgb(r, g, b);
        }

        /// <summary>
        /// Finds the centre of the found image on the RS canvas.
        /// </summary>
        /// <param name="image">The image to find.</param>
        /// <param name="rect">The bounds to find the image in.</param>
        /// <param name="mask">Skipped masked pixels with the colour Cyan (0,255,255).</param>
        /// <param name="tolerance">The tolerance of each pixel.</param>
        /// <param name="maxValue">The maximum value of the random number appended for the return type (PointRandom).</param>
        /// <returns>Returns the PointRandom found.</returns>
        public PointRandom ClickBitmap(BufferedImage image, Rectangle rect, bool mask, int tolerance)
        {
            Point p = Colour.FindBitmap(Canvas.GetCanvas(0, true), image, rect, mask, tolerance);
            if (!Decide(p))
                return new PointRandom(-1, -1, 0);
            Point sizeR = new SizeRandom(image.imageSize, p).random;
            PointRandom pr = new PointRandom(sizeR.X, sizeR.Y, 0);
            return new PointRandom(sizeR.X, sizeR.Y, 0);
        }

        /// <summary>
        /// Locates a bitmap on the screen.
        /// </summary>
        /// <param name="image">The image to search for.</param>
        /// <param name="rect">The bounds to search in.</param>
        /// <param name="mask">Skipped masked pixels with the colour Cyan (0,255,255).</param>
        /// <param name="tolerance">The tolerance of each pixel.</param>
        /// <returns>Returns the positions the bitmap was found at.</returns>
        public Point FindBitmap(BufferedImage image, Rectangle rect, bool mask, int tolerance)
        {
            return Colour.FindBitmap(Canvas.GetCanvas(0, true), image, rect, mask, tolerance);
        }

        /// <summary>
        /// Locates an array of colours on the RS canvas.
        /// </summary>
        /// <param name="rect">The bounds to find the colour in.</param>
        /// <param name="col">The colour to find.</param>
        /// <param name="tolerance">The tolerance of each pixel.</param>
        /// <returns>Returns the position of all the similar colours found.</returns>
        public List<Point> FindColours(Rectangle rect, Color col, int tolerance)
        {
            return Cluster.FindColour(Canvas.GetCanvas(0, true), rect, col, tolerance);
        }

        /// <summary>
        /// Locates an array of colours on the RS canvas in a spiral.
        /// </summary>
        /// <param name="rect">The bounds to find the colour in.</param>
        /// <param name="start">The start location of the spiral.</param>
        /// <param name="col">The colour to find.</param>
        /// <param name="tolerance">The tolerance of each pixel.</param>
        /// <returns>Returns the position of all the similar colours found.</returns>
        public List<Point> FindColoursSpiral(Rectangle rect, Point start, Color col, int tolerance)
        {
            return Cluster.FindColourSpiral(Canvas.GetCanvas(0, true), rect, start, col, tolerance);
        }

        /// <summary>
        /// Counts all the pixels in the specified region.
        /// </summary>
        /// <param name="rect">The bounds to search in (X, Y, X2, Y2).</param>
        /// <param name="c">The colour to search for.</param>
        /// <param name="tolerance">The tolerance of the pixel.</param>
        /// <returns>Returns the number of similar pixels found in that region.</returns>
        public int CountColours(Rectangle rect, Color c, int tolerance)
        {
            return Cluster.CountColours(Canvas.GetCanvas(0, true), rect, c, tolerance);
        }

        /// <summary>
        /// Dumps a point cluster of every similar colour found in the specified region.
        /// </summary>
        /// <param name="rect">The bounds to search in (X, Y, X2, Y2).</param>
        /// <param name="c">The colour to search for.</param>
        /// <param name="tolerance">The tolerance of the pixel.</param>
        /// <returns>Returns the cluster of similar pixels found in that region.</returns>
        public List<Point> DumpColours(Rectangle rect, Color c, int tolerance)
        {
            return Cluster.DumpColours(Canvas.GetCanvas(0, true), rect, c, tolerance);
        }

        /// <summary>
        /// Locates a colour on the RS canvas.
        /// </summary>
        /// <param name="rect">The bounds to find the colour in.</param>
        /// <param name="col">The colour to find.</param>
        /// <param name="tolerance">The tolerance of each pixel.</param>
        /// <returns>Returns the position the colour was found at.</returns>
        public Point FindColour(Rectangle rect, Color col, int tolerance)
        {
            return Colour.FindColour(Canvas.GetCanvas(0, true), rect, col, tolerance);
        }

        /// <summary>
        /// Finds a colour on the RS canvas.
        /// </summary>
        /// <param name="rect">The bounds to find the colour in.</param>
        /// <param name="col">The colour to find.</param>
        /// <param name="tolerance">The tolerance of each pixel.</param>
        /// <param name="maxValue">The maximum value of the random number appended for the return type (PointRandom).</param>
        /// <returns>Returns the position within the area of the found colour.</returns>
        public PointRandom ClickColour(Rectangle rect, Color col, int tolerance, int maxValue)
        {
            Point p = Colour.FindColour(Canvas.GetCanvas(0, true), rect, col, tolerance);
            return new PointRandom(p.X, p.Y, maxValue);
        }

        /// <summary>
        /// Locates a colour in a spiral on the RS canvas.
        /// </summary>
        /// <param name="rect">The bounds to find the colour in.</param>
        /// <param name="start">The start location of the spiral.</param>
        /// <param name="col">The colour to find.</param>
        /// <param name="tolerance">The tolerance of each pixel.</param>
        /// <returns>Returns the point found.</returns>
        public Point FindColourSpiral(Rectangle rect, Point start, Color col, int tolerance)
        {
            return Colour.FindColourSpiral(Canvas.GetCanvas(0, true), rect, start, col, tolerance);
        }


        /// <summary>
        /// Finds a colour in a spiral.
        /// </summary>
        /// <param name="rect">The bounds to find the colour in.</param>
        /// <param name="start">The start location of the spiral.</param>
        /// <param name="col">The colour to find.</param>
        /// <param name="tolerance">The tolerance of each pixel.</param>
        /// <param name="maxValue">The maximum value of the random number appended for the return type (PointRandom).</param>
        /// <returns>Returns the position within the area of the found colour.</returns>
        public PointRandom ClickColourSpiral(Rectangle rect, Point start, Color col, int tolerance, int maxValue)
        {
            Point p = Colour.FindColourSpiral(Canvas.GetCanvas(0, true), rect, start, col, tolerance);
            return new PointRandom(p.X, p.Y, maxValue);
        }

        /// <summary>
        /// Converts a string into a buffered image.
        /// </summary>
        /// <param name="str">The string of the image.</param>
        /// <param name="dispose">Dispose the bitmap the buffer was create from.</param>
        /// <returns>The buffered image generated from the string bitmap.</returns>
        public BufferedImage Decrypt(string str, bool dispose)
        {
            return BitmapString.Decrypt(str, dispose);
        }

        /// <summary>
        /// Finds text on the canvas.
        /// </summary>
        /// <param name="rect">The bounds to search in.</param>
        /// <param name="text">The text to search for.</param>
        /// <param name="f">The type of font to search for.</param>
        /// <param name="similarColours">The colour of the text to search for.</param>
        /// <param name="spaceTolerance">The tolerance of space between each character.</param>
        /// <param name="tolerance">The pixel tolerance.</param>
        /// <returns>Returns the point the text was found at.</returns>
        public Point FindText(Rectangle rect, string text, CharFont f, Color[] similarColours, int spaceTolerance, int tolerance)
        {
            return OCR.FindText(Canvas.GetCanvas(0, true), rect, text, f, similarColours, spaceTolerance, tolerance, false);
        }

        /// <summary>
        /// Finds text strictly on the canvas.
        /// </summary>
        /// <param name="rect">The bounds to search in.</param>
        /// <param name="text">The text to search for.</param>
        /// <param name="f">The type of font to search for.</param>
        /// <param name="similarColours">The colour of the text to search for.</param>
        /// <param name="spaceTolerance">The tolerance of space between each character.</param>
        /// <param name="tolerance">The pixel tolerance.</param>
        /// <returns>Returns the point the text was found at.</returns>
        public Point FindTextStrict(Rectangle rect, string text, CharFont f, Color[] similarColours, int spaceTolerance, int tolerance)
        {
            return OCR.FindText(Canvas.GetCanvas(0, true), rect, text, f, similarColours, spaceTolerance, tolerance, true);
        }

        /// <summary>
        /// Finds text and returns the centre point of the text found.
        /// </summary>
        /// <param name="canvas">The bitmap to find the text in.</param>
        /// <param name="rect">The bounds to search in.</param>
        /// <param name="text">The text to search for.</param>
        /// <param name="f">The type of font to search for.</param>
        /// <param name="similarColours">The colour of the text to search for.</param>
        /// <param name="spaceTolerance">The tolerance of space between each character.</param>
        /// <param name="tolerance">The pixel tolerance.</param>
        /// <returns>Returns the centre point of the text found.</returns>
        public PointRandom ClickText(Rectangle rect, string text, CharFont f, Color[] similarColours, int spaceTolerance, int tolerance)
        {
            return OCR.ClickText(Canvas.GetCanvas(0, true), rect, text, f, similarColours, spaceTolerance, tolerance, false);
        }

        /// <summary>
        /// Finds text strictly and returns the centre point of the text found.
        /// </summary>
        /// <param name="canvas">The bitmap to find the text in.</param>
        /// <param name="rect">The bounds to search in.</param>
        /// <param name="text">The text to search for.</param>
        /// <param name="f">The type of font to search for.</param>
        /// <param name="similarColours">The colour of the text to search for.</param>
        /// <param name="spaceTolerance">The tolerance of space between each character.</param>
        /// <param name="tolerance">The pixel tolerance.</param>
        /// <returns>Returns the centre point of the text found.</returns>
        public PointRandom ClickTextStrict(Rectangle rect, string text, CharFont f, Color[] similarColours, int spaceTolerance, int tolerance)
        {
            return OCR.ClickText(Canvas.GetCanvas(0, true), rect, text, f, similarColours, spaceTolerance, tolerance, true);
        }

        /// <summary>
        /// Gets the text at with the search bounds.
        /// </summary>
        /// <param name="rect">The rectangle to search for the text.</param>
        /// <param name="f">The type font to search for.</param>
        /// <param name="similarColours">The colour of the text to search for.</param>
        /// <param name="tolerance">The pixel tolerance.</param>
        /// <param name="basic">If true, only numbers (0,9) and letters (A,Z) are searched for.</param>
        /// <returns>The string found.</returns>
        public string GetText(Rectangle rect, CharFont f, Color[] similarColours, int tolerance, bool basic)
        {
            return OCR.GetText(Canvas.GetCanvas(0, true), rect, f, similarColours, tolerance, basic);
        }

        /// <summary>
        /// Returns a boolen indicating if the current player is moving or not.
        /// </summary>
        /// <returns>Returns a true boolean if your character is moving.</returns>
        public bool IsMoving()
        {
            int anime = Reflection.GetMotion();
            return anime != 0;
        }

        /// <summary>
        /// Returns a boolean indicating if the current player is animating or not.
        /// </summary>
        /// <returns>Returns a true boolean if your character is animating.</returns>
        public bool IsAnimating()
        {
            int anime = Reflection.GetAnimation();
            return anime != -1;
        }

        /// <summary>
        /// Determines if your character is in combat with another player/NPC.
        /// </summary>
        /// <returns>Returns a true boolen if your character is in combat.</returns>
        public bool InCombat()
        {
            try{return (Reflection.GetLoopStatus() > Reflection.GetLoopCycle());}
            catch{return false;}
        }

        /// <summary>
        /// Waits for the flag in the minimap until it's disappered.
        /// </summary>
        public void WaitForFlag()
        {
            Repeat:
            bool res = Decide(FindBitmap(flag, new Rectangle(540, 0, 725, 165), false, 10));
            if (res)
            {
                Sleep(new SleepRandom(500, 1000));
                goto Repeat;
            }
        }

        /// <summary>
        /// Figures out if the flag is visible.
        /// </summary>
        /// <returns>Returns true if the flag is visible.</returns>
        public bool FlagVisibile()
        {
            return Decide(FindBitmap(flag, new Rectangle(540, 0, 725, 165), false, 10));
        }

        /// <summary>
        /// Figures out if the connection is lost or not.
        /// </summary>
        /// <returns>Returns true if the connection is lost.</returns>
        public bool ConnectionLost()
        {
            return Decide(FindBitmap(conn, new Rectangle(6, 6, 236, 39), false, 3));
        }

        /// <summary>
        /// Figures out if the client is loading an interface.
        /// </summary>
        /// <returns>Return true if it is loading an interface.</returns>
        public bool IsLoading()
        {
            return Decide(FindBitmap(loading, new Rectangle(6, 6, 135, 56), false, 2));
            //return Decide(FindText(new Rectangle(6, 6, 135, 56), "Loading", CharFont.SmallChars, new Color[] {FromRGB(255, 255, 255)}, 2, 5));
        }

        /// <summary>
        /// Figures out if you're logged in or not.
        /// </summary>
        /// <returns>Return true if your logged in.</returns>
        public bool IsLoggedIn()
        {
            return Decide(FindColour(new Rectangle(424, 485, 493, 496), FromRGB(255, 255, 255), 10));
        }

        /// <summary>
        /// Figures out if your character is in the respawn location for players that got killed.
        /// </summary>
        /// <returns>Return true if you died recently.</returns>
        public bool Died()
        {
            return DistanceToTile(new Tile(3221, 3217)) < 5;
        }

        /// <summary>
        /// Gets the distance between two specified tiles.
        /// </summary>
        /// <param name="tile">The title to check the player's current location against.</param>
        /// <returns>Returns the distance between the tiles.</returns>
        public int DistanceToTile(Tile tile)
        {
            Tile charT = Reflection.GetCharacterTile();
            return (int)Math.Round(Math.Sqrt((tile.x - charT.x) * (tile.x - charT.x) + (tile.y - charT.y) * (tile.y - charT.y)));
        }

        /// <summary>
        /// Figures out if the current player is within the bounds area of the two specified tiles.
        /// </summary>
        /// <param name="topLeft">The top left corner of the area.</param>
        /// <param name="bottomRight">The bottom right corner of the area.</param>
        /// <returns>Returns true if the current player is within the bounds.</returns>
        public bool InArea(Tile topLeft, Tile bottomRight)
        {
            Tile chr = Reflection.GetCharacterTile();
            return (chr.x > topLeft.x && chr.y > topLeft.y && chr.x < bottomRight.x && chr.y < bottomRight.y);
        }

        /// <summary>
        /// Figures out if you're on the specified tile.
        /// </summary>
        /// <param name="theTile">The tile to check.</param>
        /// <returns>Returns true if you're on the tile.</returns>
        public bool OnTile(Tile theTile)
        {
            Tile chr = Reflection.GetCharacterTile();
            return (chr.x == theTile.x) && (chr.y == theTile.y);
        }

        /// <summary>
        /// Figures out if the tile specified is on the minimap.
        /// </summary>
        /// <param name="theTile">The tile to check.</param>
        /// <returns>Returns true if the tile is on the minimap.</returns>
        public bool TileOnMinimap(Tile theTile)
        {
            return Reflection.PossibleMinimapClick(theTile);
        }

        /// <summary>
        /// Walk to a single tile.
        /// </summary>
        /// <param name="t">The tile to walk to.</param>
        /// <returns>Returns true if the tile walk succeeded.</returns>
        public bool WalkTo(Tile t, int offset)
        {
            //i'm to lazy to write a single tile walk function. deriving it from TilePath's single walk.
            TilePath tp = new TilePath(this, new Tile[] { t });
            tp.TileWalkTo(0, offset);
            return true;
        }
    }
}
